/**
 * @file common.c
 * NDN NAC common functions
 * Chengyu Fan <chengyu@cs.colostate.edu>
 */

#include "common.h"

#if defined(__APPLE__) && defined(__MACH__) || defined(__FreeBSD__) || defined(__NETBSD__) || defined(__OpenBSD__)
void
get_hw_addr(const char *name, struct hardware *hw) {
	struct ifaddrs *ifa;
	struct ifaddrs *p;
	struct sockaddr_dl *sa;

	if (getifaddrs(&ifa) != 0) {
		printf("Error getting interface information; %m");
                exit(1);
	}

	/*
	 * Loop through our interfaces finding a match.
	 */
	sa = NULL;
	for (p=ifa; (p != NULL) && (sa == NULL); p = p->ifa_next) {
		if ((p->ifa_addr->sa_family == AF_LINK) && 
		    !strcmp(p->ifa_name, name)) {
		    	sa = (struct sockaddr_dl *)p->ifa_addr;
		}
	}
	if (sa == NULL) {
		printf("No interface called '%s'", name);
                exit(1);
	}

	/*
	 * Pull out the appropriate information.
	 */
        switch (sa->sdl_type) {
                case IFT_ETHER:
                        hw->hlen = sa->sdl_alen + 1;
                        hw->hbuf[0] = HTYPE_ETHER;
                        memcpy(&hw->hbuf[1], LLADDR(sa), sa->sdl_alen);
                        break;
		case IFT_ISO88023:
		case IFT_ISO88024: /* "token ring" */
		case IFT_ISO88025:
		case IFT_ISO88026:
                        hw->hlen = sa->sdl_alen + 1;
                        hw->hbuf[0] = HTYPE_IEEE802;
                        memcpy(&hw->hbuf[1], LLADDR(sa), sa->sdl_alen);
                        break;
#ifdef IFT_FDDI
                case IFT_FDDI:
                        hw->hlen = sa->sdl_alen + 1;
                        hw->hbuf[0] = HTYPE_FDDI;
                        memcpy(&hw->hbuf[1], LLADDR(sa), sa->sdl_alen);
                        break;
#endif /* IFT_FDDI */
                default:
                        printf("Unsupported device type %d for \"%s\"",
                                  sa->sdl_type, name);
                        exit(1);
        }

	freeifaddrs(ifa);
}

#endif

#ifdef __linux__
void
get_hw_addr(const char *name, struct hardware *hw) {
	int sock;
	struct ifreq tmp;
	struct sockaddr *sa;

	if (strlen(name) >= sizeof(tmp.ifr_name)) {
		printf("Device name too long: \"%s\"", name);
	}

	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) {
		printf("Can't create socket for \"%s\": %m", name);
                exit(1);
	}

	memset(&tmp, 0, sizeof(tmp));
	strcpy(tmp.ifr_name, name);
	if (ioctl(sock, SIOCGIFHWADDR, &tmp) < 0) {
		printf("Error getting hardware address for \"%s\": %m", 
			  name);
                exit(1);
	}

	sa = &tmp.ifr_hwaddr;
	switch (sa->sa_family) {
		case ARPHRD_ETHER:
			hw->hlen = 7;
			hw->hbuf[0] = HTYPE_ETHER;
			memcpy(&hw->hbuf[1], sa->sa_data, 6);
			break;
		case ARPHRD_IEEE802:
#ifdef ARPHRD_IEEE802_TR
		case ARPHRD_IEEE802_TR:
#endif /* ARPHRD_IEEE802_TR */
			hw->hlen = 7;
			hw->hbuf[0] = HTYPE_IEEE802;
			memcpy(&hw->hbuf[1], sa->sa_data, 6);
			break;
		case ARPHRD_FDDI:
			hw->hlen = 17;
			hw->hbuf[0] = HTYPE_FDDI;
			memcpy(&hw->hbuf[1], sa->sa_data, 16);
			break;
		default:
			printf("Unsupported device type %ld for \"%s\"",
				  (long int)sa->sa_family, name);
                        exit(1);
	}

	close(sock);
}
#endif

int
get_random(){
	srand((int) time(0));
	return rand();
}

int
readable_time(int fd, int usec){
	fd_set rset;
	struct timeval tv;
    
	FD_ZERO(&rset);
	FD_SET(fd, &rset);
    
	tv.tv_sec = 0;
	tv.tv_usec = usec*100000;

	return (select(fd+1, &rset, NULL, NULL, &tv));
}

void
get_face_name (char *face_name, char *ip){
	struct ifaddrs *addrs, *iap;
	struct sockaddr_in *sa;
	char buf[32];

	getifaddrs(&addrs);
	for (iap = addrs; iap != NULL; iap = iap->ifa_next) {
		if (iap->ifa_addr && (iap->ifa_flags & IFF_UP) && iap->ifa_addr->sa_family == AF_INET) {
			sa = (struct sockaddr_in *)(iap->ifa_addr);
			inet_ntop(iap->ifa_addr->sa_family, (void *)&(sa->sin_addr), buf, sizeof(buf));
			if (!strcmp(ip, buf)) {
				strcpy(face_name, iap->ifa_name);
			}
		}
	}
	freeifaddrs(addrs);
}

